unit main;

{$mode objfpc}{$H+}

interface

uses
 Classes, SysUtils, FileUtil, UTF8Process, Forms, Controls, Graphics, Dialogs,
 ComCtrls, StdCtrls, ExtCtrls, Spin, Grids, uComm, SynaSer, rutrans, uNetChoice;

type

  { TForm1 }

  TForm1 = class(TForm)
    btnEnt: TButton;
    Button1: TButton;
    Button2: TButton;
    BtnUssdEnt: TButton;
    btnUSSDStop: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    btnNetScan: TButton;
    btnChooseNet: TButton;
    Button6: TButton;
    Button7: TButton;
    btnConnect: TButton;
    btnDecode: TButton;
    btnGetData: TButton;
    btnDeleteMsg: TButton;
    cbPort: TComboBox;
    eAPN: TEdit;
    ePass: TEdit;
    eUserName: TEdit;
    eUSSDIn: TEdit;
    eTermIn: TEdit;
    Label1: TLabel;
    Label10: TLabel;
    Label11: TLabel;
    Label12: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    Label9: TLabel;
    lRslt: TLabel;
    mDecode: TMemo;
    mWvScript: TMemo;
    mUSSDOut: TMemo;
    mTermOut: TMemo;
    PageControl1: TPageControl;
    sgSMS: TStringGrid;
    tsSMSRead: TTabSheet;
    wvdProcess: TProcessUTF8;
    rbNotChange: TRadioButton;
    rbLTE: TRadioButton;
    rbFast: TRadioButton;
    rbModeAny: TRadioButton;
    RadioGroup1: TRadioGroup;
    seTimOut: TSpinEdit;
    sgNetState: TStringGrid;
    sgNets: TStringGrid;
    seScanWait: TSpinEdit;
    tsConnect: TTabSheet;
    tsNetwork: TTabSheet;
    tsUSSD: TTabSheet;
    Timer1: TTimer;
    tsConfig: TTabSheet;
    tsMiniTerm: TTabSheet;
    procedure btnChooseNetClick(Sender: TObject);
    procedure btnConnectClick(Sender: TObject);
    procedure btnDecodeClick(Sender: TObject);
    procedure btnDeleteMsgClick(Sender: TObject);
    procedure btnEntClick(Sender: TObject);
    procedure btnGetDataClick(Sender: TObject);
    procedure btnNetScanClick(Sender: TObject);
    procedure BtnUssdEntClick(Sender: TObject);
    procedure btnUSSDStopClick(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button6Click(Sender: TObject);
    procedure Button7Click(Sender: TObject);
    procedure cbPortChange(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure mWvScriptChange(Sender: TObject);
    procedure sgSMSDblClick(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);

  private
    { private declarations }
  public
    Ser:TBlockSerial;
    USSDWaiting:boolean;
    procedure ParseUSSD(const s:string);
    procedure SetMode;
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.cbPortChange(Sender: TObject);
var
  s: String;
begin
  s:=cbPort.Text;
  if not FileExistsUTF8(s) then exit//ShowMessage('Ошибка: не могу найти указанный порт')
    else PortName:=s;
end;



procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  if Assigned(Ser) then try Ser.CloseSocket;Ser.Free;except end;

  CloseAction:=caFree;
  //todo
 // halt;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  USSDWaiting:=false;
  sgNetState.Cells[0,0]:='Режим выбора';
  sgNetState.Cells[1,0]:='Название сети';
  sgNetState.Cells[2,0]:='Режим работы';
  sgNetState.Cells[3,0]:='Уровень сигнала';
  sgNets.Cells[0,0]:='Возм.регистрации';
  sgNets.Cells[1,0]:='Название';
  sgNets.Cells[2,0]:='Код сети';
  sgNets.Cells[3,0]:='Режим работы';

  {$IFDEF MSWINDOWS}
  cbPort.Text:='COM4:';
  cbPort.Items.Clear;
  for i:=1 to 19 do
    cbPort.Items.Add('COM'+IntToStr(i)+':');
  tsConnect.Visible:=false;
  {$ENDIF}

end;

procedure TForm1.mWvScriptChange(Sender: TObject);
begin

end;

procedure TForm1.sgSMSDblClick(Sender: TObject);
var
  N:integer;
begin
  N:=sgSMS.Selection.Top;
{  ShowMessage('L='+IntToStr(R.Left)+';T='+IntToStr(R.Top)+
    ';R='+IntToStr(R.Right)+';B='+IntToStr(R.Bottom));}
  if (N<=0)or(N>=sgSMS.ColCount) then exit;
  with sgSMS do
  ShowMessage('Сообщение №'+Cells[0,n]+'Тип: '+Cells[1,n]+'; Дата/время='+Cells[2,n]+LineEnding+
  'Отправитель: '+Cells[3,n]+LineEnding+'Текст: '+Cells[4,n]);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var


  s: String;
begin
  try
    s := Ser.RecvString(500);
//    if s<>'' then writeln(s);
    if USSDWaiting and (LeftStr(s,6)='+CUSD:') then ParseUSSD(s) else
    if s<>'' then  mTermOut.Lines.Add(s);
  except
  end;
end;

procedure TForm1.ParseUSSD(const s: string);
var s1,s2:string;
  i: Integer;
//  a,b,c,d: Char;
 // SL:TStringList;
  Coded: Boolean;
begin
  s1:='';
  mUSSDOut.Lines.Add('Ответ USSD:');
  Coded:=true;
  i:=1;
  s1:='';
  while (i<=length(s))and (s[i]<>'"') do inc(i);
  if i>length(s) then begin
    mUSSDOut.Lines.Add('Ошибка распознавания ответа');
    USSDWaiting:=false;
    btnUSSDStop.Hide;
    exit;
  end;
  inc(i);
  while (i<=length(s))and (s[i]<>'"') do begin s1:=s1+s[i];inc(i);end;
  if Coded then begin
    s1:=Uncode(s1);
  end;
  mUSSDOut.Lines.Add(s1);
  USSDWaiting:=false;
  btnUSSDStop.Hide;
end;

procedure TForm1.SetMode;
var
  cmd: String;
begin
  //Коды взяты с сайта 4pda
  if not Assigned(Ser) then exit;
  if rbNotChange.Checked then exit;
  if rbModeAny.Checked then
      cmd:='AT^SYSCFGEX="00",3fffffff,2,4,7fffffffffffffff,,';
  if rbFast.Checked then
      cmd:='AT^SYSCFGEX="0302",3FFFFFFF,1,2,7FFFFFFFFFFFFFFF,,';
  if rbLTE.Checked then
      cmd:='AT^SYSCFGEX="03",3fffffff,2,4,7fffffffffffffff,,';
  try
    ser.ATCommand(cmd);
  except
  end;
end;

procedure TForm1.btnEntClick(Sender: TObject);
var
  s: String;
begin
  try
    Ser.AtTimeout:=seTimOut.Value*1000;
    mTermOut.Text:=mTermOut.Text+eTermIn.Text;
    mTermOut.Text:=mTermOut.Text+Ser.ATCommand(eTermIn.Text);
  except
    on E:Exception do
    begin
      mTermOut.Lines.Add(E.Message);
    end;
  end;
end;

procedure TForm1.btnGetDataClick(Sender: TObject);
var
  s: String;
  i: integer;
  SL: TStringList;
  s1: String;
  N: Integer;
  s2: String;
  j: Integer;
begin
  try
    ser.ATCommand('AT+CSCS="UCS2"');
    ser.ATCommand('AT+CMGF=1');
    s:=ser.ATCommand('AT+CMGL="ALL"');
    if copy(s,1,6)<>'+CMGL:' then raise EInOutError.Create('Ошибка распознавания строки');
    s:=Trim(CopyToEnd(s,7));
    i:=pos(',',s);
    if i<=0 then s1:=s else s1:=copy(s,1,i-1);
    N:=StrToIntDef(s1,-2)+1;
    if N<=0 then raise EInOutError.Create('Нет сообщений');
    sgSMS.RowCount:=N+1;
    for i:=1 to N do
    with sgSMS do
    begin
      Cells[0,i]:=IntToStr(i);
      s:=ser.ATCommand('AT+CMGR='+IntToStr(i-1));
      if length(s)<7 then begin ShowMessage('Ошибка чтения сообщения '+IntToStr(i));continue;end;
      while s[1] in [' ',#10,#13] do s:=copy(s,2,length(s));
      if copy(s,1,6)<>'+CMGR:' then
        begin ShowMessage('Ошибка чтения сообщения '+IntToStr(i)+': '+copy(s,1,6));continue;end;
      SL:=TStringList.Create;
      s:=Trim(CopyToEnd(s,7));
      s:=StrReplace(s,#13#10,',');
      CommaParser(s,',',SL);
      if SL.Count>0 then Cells[1,i]:=DeQuote(SL[0]);
      if SL.Count>1 then Cells[3,i]:=Uncode(DeQuote(SL[1]));
      if SL.Count>3 then Cells[2,i]:=DeQuote(SL[3]);
      if SL.Count>4 then
      begin
        s1:=trim(DeQuote(SL[4]));
        s2:='';
        for j:=1 to length(s1) do
         case s1[j] of
          ' ','"',#10,#13:continue;
          '0'..'9','A'..'F':s2:=s2+s1[j];
         else break;
         end;
        Cells[4,i]:=Uncode(s2);

      end;
    end;
  except
    on e:Exception do  ShowMessage(E.Message);

  end;
  //vvi
end;

procedure TForm1.btnChooseNetClick(Sender: TObject);
var
  R: TGridRect;
  s: String;
  s1: String;
begin
  R:=sgNets.Selection;
  if not Assigned(Ser) then exit;
  if (R.Bottom-R.Top)<>0 then begin
    ShowMessage('Выбрано более одной сети');
    exit;
  end;
  if (R.Top<0)or(R.Top>=sgNets.RowCount) then begin
    ShowMessage('Не выбрана сеть');
    exit;
  end;
  s:=sgNets.Cells[3,R.Top];
  if s='' then s:='2';
  s1:=sgNets.Cells[2,R.Top];

  if (length(s1)>1)and(s1[1]='"')and(s1[length(s1)]='"')then
  s1:=copy(s1,2,length(s1)-2);
  try
    Ser.AtTimeout:=seScanWait.Value*3000;
    s:=Ser.ATCommand('AT+COPS=1,2,'+s1+','+s[1]);
    Ser.AtTimeout:=seTimOut.Value*1000;
    lRslt.Caption:=s;
  except
    on E:Exception do ShowMessage(E.Message);
  end;
end;

procedure TForm1.btnConnectClick(Sender: TObject);
var
  TF,S: String;
  SL: TStringList;

begin
  TF:=SysUtils.GetTempFileName;
  SL:=TStringList.Create;
  s:=mWvScript.Text;
  s:=StrReplace(S,'#%DEVICE%#',cbPort.Text);
  s:=StrReplace(S,'#%APN%#',eAPN.Text);
  s:=StrReplace(S,'#%USER%#',eUserName.Text);
  s:=StrReplace(S,'#%PASSWORD%#',ePass.Text);
  SL.Text:=s;
  SL.SaveToFile(TF);
  PageControl1.ActivePage:=tsMiniTerm;
  Application.ProcessMessages;
  wvdProcess.Parameters.Clear;
  wvdProcess.Parameters.Add('-C '+TF);
//  wvdProcess.WaitOnExit;
  wvdProcess.Execute;
end;

procedure TForm1.btnDecodeClick(Sender: TObject);
begin
  mDecode.Text:=Uncode(mDecode.Text);
end;

procedure TForm1.btnDeleteMsgClick(Sender: TObject);
var
  R: TGridRect;
  i: LongInt;
begin
  R:=sgSMS.Selection;
  with sgSMS do
  if MessageDlg('Удаление сообщений','Вы действительно хотите удалить сообщения с '+
  Cells[0,R.Top]+' по '+Cells[0,R.Bottom]+'?',mtConfirmation,[mbYes,mbNo],-1)<>mrYes
   then exit;
  for i:=R.Bottom downto R.Top do
  begin
    ser.ATCommand('AT+CMGD='+sgSMS.Cells[0,i]);
    Application.ProcessMessages;
  end;

end;

procedure TForm1.BtnUssdEntClick(Sender: TObject);
begin
  try
    ser.ATCommand('AT^USSDMODE=0');
    ser.ATCommand('AT+CSCS="UCS2"');
    ser.ATCommand('AT+CUSD=1,"'+eUSSDIn.Text+'",15');
    mUSSDOut.Lines.Add(eUSSDIn.Text);
    USSDWaiting:=true;
    btnUssdStop.Show;
  except
  end;
end;

procedure TForm1.btnUSSDStopClick(Sender: TObject);
begin
  USSDWaiting:=false;
  btnUSSDStop.Hide;
  mUSSDOut.Lines.Add('Ожидание прекращено!');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Ser:=TBlockSerial.Create;
  Ser.RaiseExcept:=true;
  mTermOut.Lines.Add('Connecting '+PortName+CRLF);
  try
    Ser.Connect(PortName);
    Ser.Config(960000,8,'N',0,false,false);


  except
    on E:Exception do
    begin
      mTermOut.Lines.Add(E.Message);
      Ser.Free;exit;
    end;
  end;
  eTermIn.Enabled:=True;
  BtnEnt.Enabled:=true;
  Timer1.Enabled:=true;
  Button2.Show;
  eUSSDIn.Enabled:=true;
  BtnUssdEnt.Enabled:=true;
  tsNetwork.Enabled:=true;
  SetMode;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if Assigned(Ser) then begin ser.CloseSocket; ser.free;end;
  Ser:=nil;
  Button2.Hide;
  eTermIn.Enabled:=false;
  Timer1.Enabled:=false;
  BtnEnt.Enabled:=false;
  tsNetwork.Enabled:=false;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  mUSSDOut.Clear;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  mTermOut.Clear;
end;

procedure TForm1.btnNetScanClick(Sender: TObject);
var
  SL,SL1: TStringList;
  s: String;
  i: Integer;
  j: Integer;
begin
  if not Assigned(Ser) then begin ShowMessage('Нет подключения!');exit; end;
  SL:=TStringList.Create;
  Ser.AtTimeout:=seScanWait.Value*1000;
  try
    SL.Text:=Ser.ATCommand('AT+COPS=?');
  except
    ShowMessage('Не удалось получить список сетей');
  end;
  Ser.AtTimeout:=seTimOut.Value*1000;
   s:='';
  for i:=0 to SL.Count-1 do
    if LeftStr(SL[i],6)='+COPS:' then begin s:=RightStr(SL[i],Length(SL[i])-6);break; end;
  if s='' then begin ShowMessage('Не удалось получить список сетей!');exit; end;
  CommaParser(s,',',SL);
  i:=0;
  SL1:=TStringList.Create;
  while i<SL.Count do
  begin
    s:=Trim(SL[i]);
    if s='' then break;
    if (s[1]<>'(') or (s[Length(s)]<>')') then continue;
    s:=copy(s,2,length(s)-2);
    CommaParser(s,',',SL1);
    if sgNets.RowCount<=i+1 then sgNets.RowCount:=sgNets.RowCount+1;
    for j:=0 to 3 do sgNets.Cells[j,i+1]:='';
    if SL.Count=0 then begin sgNets.Cells[0,i+1]:='Нет сети'; inc(i);continue end;
    s:=Trim(SL1[0]);
    if s='0' then sgNets.Cells[0,i+1]:='Неизв.' else
    if s='1' then sgNets.Cells[0,i+1]:='Разрешено' else
    if s='2' then sgNets.Cells[0,i+1]:='Текущая сеть' else
    if s='3' then sgNets.Cells[0,i+1]:='Запрещено' else
     sgNets.Cells[0,i+1]:='Нет данных';
    if SL1.Count=1 then begin inc(i);continue;end;
    sgNets.Cells[1,i+1]:=SL1[1];
    if SL1.Count<=3 then begin inc(i);continue;end;
    sgNets.Cells[2,i+1]:=SL1[3];
    if SL.Count<=4 then begin inc(i);continue;end;
    s:=trim(SL1[4]);
    if s='0' then sgNets.Cells[3,i+1]:='0(GSM,2G)' else
    if s='2' then sgNets.Cells[3,i+1]:='2(UMTS,3G)' else
    if s='7' then sgNets.Cells[3,i+1]:='7(LTE,4G)' else
      sgNetS.Cells[3,1]:=s+'(Неизвестно)';
    inc(i);
  end;
end;

procedure TForm1.Button5Click(Sender: TObject);
var SL:TStringList;
  i: Integer;
  s: String;
begin
  if not Assigned(Ser) then begin ShowMessage('Нет подключения!');exit; end;
  SL:=TStringList.Create;
  SL.Text:=Ser.ATCommand('AT+COPS?');
  s:='';
  for i:=0 to SL.Count-1 do
    if LeftStr(SL[i],6)='+COPS:' then begin s:=RightStr(SL[i],Length(SL[i])-6);break; end;
  if s='' then begin ShowMessage('Ошибка получения информации!');exit; end;
  CommaParser(s,',',SL);
  if SL.Count=0 then begin ShowMessage('Ошибка получения информации!');exit; end;
  s:=trim(SL[0]);
  if s='0' then sgNetState.Cells[0,1]:='Авто' else
  if s='1' then sgNetState.Cells[0,1]:='Ручной' else
  if s='4' then sgNetState.Cells[0,1]:='Любой' else
    sgNetState.Cells[0,0]:='Неизвестный';
  if SL.Count>=3 then
  begin
    s:=trim(SL[2]);
    sgNetState.Cells[1,1]:=s;
    if SL.Count>=4 then
    begin
      s:=trim(SL[3]);
      if s='0' then sgNetState.Cells[2,1]:='0(GSM,2G)' else
      if s='2' then sgNetState.Cells[2,1]:='2(UMTS,3G)' else
      if s='7' then sgNetState.Cells[2,1]:='7(LTE,4G)' else
        sgNetState.Cells[2,1]:=s+'(Неизвестно)';
    end;

  end;
  SL.Text:=Ser.ATCommand('AT+CSQ');
  s:='';
  for i:=0 to SL.Count-1 do
    if LeftStr(SL[i],5)='+CSQ:' then begin s:=RightStr(SL[i],Length(SL[i])-5);break; end;
  if s='' then exit;
  CommaParser(s,',',SL);
  if SL.Count=0 then exit;
  i:=StrToIntDef(Trim(SL[0]),-1);
  if i<0 then exit;
  i:=-113+i*2;
  sgNetState.Cells[3,1]:=IntToStr(i)+' дБ';
end;

procedure TForm1.Button6Click(Sender: TObject);
begin
  if not Assigned(Ser) then begin
    ShowMessage('Нет подключения, невозможно применить режим');
    exit;
  end;
  SetMode;
end;

procedure TForm1.Button7Click(Sender: TObject);
var
  s: String;
begin
  frmNetChoice.ShowModal;
  try
  with frmNetChoice do
    s:='AT+COPS='+cbMode.Text[1]+',2,'+eOperCode.Text+','+cbNetMode.Text[1];
  except
    ShowMessage('Неправильный ввод');
  end;
   try
    Ser.AtTimeout:=seScanWait.Value*3000;
    s:=Ser.ATCommand(s);
    Ser.AtTimeout:=seTimOut.Value*1000;
    lRslt.Caption:=s;
  except
    on E:Exception do ShowMessage(E.Message);
  end;
end;

end.

